/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.store.client.components;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.elf.gwt.common.client.access.RequestParameter;
import com.elf.gwt.common.client.callback.TableNavigatorWidgetCallback;
import com.elf.gwt.common.client.components.CommonSimpleComponent;
import com.elf.gwt.common.client.model.CategoryModel;
import com.elf.gwt.common.client.model.ManufacturerModel;
import com.elf.gwt.common.client.model.OrderbyModel;
import com.elf.gwt.common.client.model.ProductModel;
import com.elf.gwt.common.client.model.ProductReviewModel;
import com.elf.gwt.common.client.utils.CommonUtils;
import com.elf.gwt.common.client.widget.TableNavigatorWidget;
import com.elf.gwt.store.client.GWTCommerceConstants;
import com.elf.gwt.store.client.StoreComponentController;
import com.elf.gwt.store.client.utils.StoreUtils;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;

/**
 *  
 */
public class ProductReviewsComponent extends ProductsComponent
{	
	protected List<ProductReviewModel> productReviewModels;
	protected ProductReviewModel productReviewModel;
	protected TableNavigatorWidget navPanelTop;
	protected TableNavigatorWidget navPanelBot;
	protected List<OrderbyModel> orderbyModels = null;

	/**
	 * Constructor
	 */
	public ProductReviewsComponent(StoreComponentController controller, String stylePrefix)
	{
		super(controller, stylePrefix, null, false);
		productReviewModel = new ProductReviewModel();
		setClearManufacturerId(true);
		productReviewModels = new ArrayList<ProductReviewModel>();
	}

	public boolean updateFromHistoryParameters(String[] params)
	{
		int productId = StoreComponentController.productComponent.getProductModel().getId();
		int categoryId = StoreComponentController.categoriesComponent.getCategoryModel().getId();
		int manufacturerId = StoreComponentController.manufacturersComponent.getManufacturerModel().getId();
		int offset = 0;
		String orderby = "*";
		
		try {
			productId = Integer.parseInt(params[1]);
			categoryId = Integer.parseInt(params[2]);
			manufacturerId = Integer.parseInt(params[3]);
			offset = Integer.parseInt(params[4]);
			orderby = params[5];
		}
		catch (Exception e) {}
		if (orderby.equals("*")) orderby = "r.last_modified desc";

		StoreComponentController.productComponent.getProductModel().update(categoryId, productId, "");
		
		CategoryModel cmodel = StoreComponentController.categoriesComponent.getCategoryModel(categoryId);
		StoreComponentController.categoriesComponent.getCategoryModel().update(cmodel);

		if (manufacturerId != StoreComponentController.manufacturersComponent.getManufacturerModel().getId())
		{
			ManufacturerModel mmodel = StoreComponentController.manufacturersComponent.getManufacturerModelById(manufacturerId);
			StoreComponentController.manufacturersComponent.getManufacturerModel().update(mmodel);
			StoreComponentController.manufacturersComponent.rebuild();
			storeController.getMultipleResultsComponent().addComponent(StoreComponentController.categoriesComponent);
		}
		
		productReviewModel.setOffset(offset);
		productReviewModel.setOrderby(orderby);
		
		storeController.getMultipleResultsComponent().addComponent(this);

		//Don't look for new products
		CommonSimpleComponent alwaysAskComponent = controller.getComponent("NewProductsComponent", false);
		if (alwaysAskComponent != null) storeController.getMultipleResultsComponent().removeComponent(alwaysAskComponent);

		return super.updateFromHistoryParameters(params);
	}

	/**
	 * add the additional request parameters for searching.
	 */
	public void additionalRequestParameters()
	{
		super.additionalRequestParameters();
		addRequestParameter(new RequestParameter("review_offset", productReviewModel.getOffset()));
		addRequestParameter(new RequestParameter("review_orderby", productReviewModel.getOrderby()));
	}

	protected void buildModel(JSONArray jsonArray) throws Exception
	{
		productReviewModels.clear();
		super.buildModel(jsonArray);
	}

	protected void buildModel(JSONObject jsonObject) throws Exception
	{
		ProductModel productModel = new ProductModel(jsonObject, productMetaModel.getImageWidthMax(), productMetaModel.getImageHeightMax());
		ProductReviewModel productReviewModel = new ProductReviewModel(jsonObject);
		productReviewModels.add(productReviewModel);
		productModels.add(productModel);
	}

	public void buildFromModel() throws Exception
	{
		GWTCommerceConstants constants = storeController.getStoreConstants();
		VerticalPanel bodyPanel = new VerticalPanel();
		bodyPanel.setWidth("100%");
		bodyPanel.addStyleName(getHandle() + "BodyPanel");
		panel.setWidget(1, 0, bodyPanel);

		//Order By

		if (orderbyModels == null)
		{
			orderbyModels = new ArrayList<OrderbyModel>();

			String orderbyDelimiter = " " + constants.ProductReviewsComponentOrderbyDelimiter() + " ";
			String ascending = orderbyDelimiter + constants.ProductReviewsComponentOrderbyAscending();
			String descending = orderbyDelimiter + constants.ProductReviewsComponentOrderbyDescending();

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyName() + ascending, "pd.products_name"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyName() + descending, "pd.products_name desc"));

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyModel() + ascending, "p.products_model"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyModel() + descending, "p.products_model desc"));

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyPrice() + ascending, "p.products_price"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyPrice() + descending, "p.products_price desc"));

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyAccount() + ascending, "r.customers_name"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyAccount() + descending, "r.customers_name desc"));

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyRating() + ascending, "r.reviews_rating"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyRating() + descending, "r.reviews_rating desc"));

			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyDateAdded() + ascending, "r.date_added"));
			orderbyModels.add(new OrderbyModel(constants.ProductReviewsComponentOrderbyDateAdded() + descending, "r.date_added desc"));

			orderbyModels.add(new OrderbyModel("Date Modified" + ascending, "r.last_modified"));
			orderbyModels.add(new OrderbyModel("Date Modified" + descending, "r.last_modified desc"));
		}
		
		String orderby = productReviewModel.getOrderby();
		if (orderby != null && orderby.length() > 0)
		{
			Iterator<OrderbyModel> iter = orderbyModels.iterator();
			while (iter.hasNext())
			{
				OrderbyModel orderbyModel = iter.next();
				if (orderby.equals(orderbyModel.getOrderclause())) {
					orderbyModel.setSelected(true);
				}
				else {
					orderbyModel.setSelected(false);
				}
			}
		}

		//Top Navigation
		if (productMetaModel.getPrevNextBarLocation() == 1 || productMetaModel.getPrevNextBarLocation() == 3)
		{
			if (navPanelTop == null)
			{
				navPanelTop = new TableNavigatorWidget(constants.ProductReviewsComponentReviews(), productMetaModel.getTotalRows(), 
						productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset(), 
						productMetaModel.getPageLinksMax(), orderbyModels,
						controller.getCommonConstants(), StoreComponentController.languagesComponent.getLanguageModel().getCode(), new PRTableNavigatorCallback(),
						CommonUtils.getImageDirectory());
			}
			else
			{
				navPanelTop.refresh(productMetaModel.getTotalRows(), productMetaModel.getMaxRows(), 
						productMetaModel.getRows(), productMetaModel.getOffset());
			}

			bodyPanel.add(navPanelTop);
			navPanelTop.setStyleName(getHandle() + "NavigationPanel");
		}
		//Table
		int sz = productModels.size();
		int colnum = 3;
		Grid bodyTable = new Grid(sz+1, colnum);
		bodyTable.setStyleName(getHandle() + "BodyTable");
		CellFormatter cf = bodyTable.getCellFormatter();
		bodyPanel.add(bodyTable);

		//Heading
		InlineLabel label1 = new InlineLabel(constants.ProductReviewsComponentImageTitle());
		InlineLabel label2 = new InlineLabel(constants.ProductReviewsComponentReviewTitle());
		InlineLabel label3 = new InlineLabel(constants.ProductReviewsComponentButtonsTitle());
		bodyTable.setWidget(0, 0, label1);
		bodyTable.setWidget(0, 1, label2);
		bodyTable.setWidget(0, 2, label3);
		cf.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
		cf.setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER);
		cf.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_CENTER);
		cf.setStyleName(0, 0, getHandle() + "BodyTableTitle");
		cf.setStyleName(0, 1, getHandle() + "BodyTableTitle");
		cf.setStyleName(0, 2, getHandle() + "BodyTableTitle");

		//Bottom Navigation
		if (productMetaModel.getPrevNextBarLocation() == 2 || productMetaModel.getPrevNextBarLocation() == 3)
		{
			if (navPanelBot == null)
			{
				navPanelBot = new TableNavigatorWidget(constants.ProductReviewsComponentReviews(), productMetaModel.getTotalRows(), 
						productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset(), 
						productMetaModel.getPageLinksMax(), orderbyModels,
						controller.getCommonConstants(), StoreComponentController.languagesComponent.getLanguageModel().getCode(), new PRTableNavigatorCallback(),
						CommonUtils.getImageDirectory());
			}
			else
			{
				navPanelBot.refresh(productMetaModel.getTotalRows(), productMetaModel.getMaxRows(), 
						productMetaModel.getRows(), productMetaModel.getOffset());
			}

			bodyPanel.add(navPanelBot);
			navPanelBot.setStyleName(getHandle() + "NavigationPanel");
		}

		String delimiter = constants.ProductReviewsComponentDelimiter();

		if (StoreComponentController.productComponent.getProductModel().getId() > 0 && sz > 0) {
			StoreComponentController.productComponent.getProductModel().update(productModels.get(0));
		}
		
		int productModelId = -1;
		for (int i = 0; i < sz; i++)
		{
			ProductModel productModel = productModels.get(i);
			ProductReviewModel productReviewModel = productReviewModels.get(i);

			VerticalPanel vpanel1 = new VerticalPanel();
			VerticalPanel vpanel2 = new VerticalPanel();
			VerticalPanel vpanel3 = new VerticalPanel();

			if (productModelId != productModel.getId())
			{
				Image image = new Image();
				image.setStyleName("ComponentImage");
				image.addStyleName(getHandle() + "Image");
				image.addStyleName("ComponentLink");
				image.addStyleName("index:" + i);
				image.setUrl(StoreUtils.getImageProductsDirectory() + productModel.getImage());
				image.addClickHandler(productClickHandler);
				String[] imageSize = productModel.getImageSize();
				image.setSize(imageSize[0], imageSize[1]);
				image.setTitle(productModel.getName());
				vpanel1.add(image);
			}

			if (productModelId != productModel.getId())
			{
				String name = productModel.getName();
				InlineHTML nameLabel = new InlineHTML("<strong>" + constants.ProductReviewsComponentName() + delimiter + "</strong>" + " " + name);
				nameLabel.addStyleName("ComponentLink");
				nameLabel.addStyleName("index:" + i);
				nameLabel.addClickHandler(productClickHandler);
				vpanel2.add(nameLabel);

				String model = productModel.getModel();
				vpanel2.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentModel() + delimiter + "</strong>" + " " + model));

				String priceOut = CommonUtils.productPriceDisplay(StoreComponentController.currenciesComponent.getCurrencyModel(), productModel.getPrice(), 
						productModel.getDiscountPrice(), productModel.getSpecialPrice());
				if (productModel.getWeight() < 0.00001 && !productModel.isVirtual()) priceOut += "<br/><strong>Shipping" + delimiter + "</strong> Free!";
				vpanel2.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentPrice() + delimiter + "</strong>" + " " + priceOut));
			}
			vpanel2.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentAccount() + delimiter + "</strong>" + " " + productReviewModel.getAccountName()));

			HorizontalPanel reviewPanel = new HorizontalPanel();
			reviewPanel.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentRating() + delimiter + "</strong>" + " "));

			Image reviewImage = new Image();
			reviewImage.setUrl(this.getImageCommonDirectory() + "stars_" + productReviewModel.getRating() + ".gif");
			reviewPanel.add(reviewImage);
			vpanel2.add(reviewPanel);

			vpanel2.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentDateAdded() + delimiter + "</strong>" + " " + DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_MEDIUM).format(productReviewModel.getDateAdded())));

			String review = productReviewModel.getReviewText();
			review = CommonUtils.breakString(review, 30, ' ');
			vpanel2.add(new InlineHTML("<strong>" + constants.ProductReviewsComponentReview() + delimiter + "</strong>" + " " + review));

			if (productModelId != productModel.getId())
			{
				//Buttons
				Button buynowButton = new Button(controller.getCommonConstants().BuyNow(), cartClickHandler);
				buynowButton.addStyleName(getHandle() + "BodyTableButton");
				buynowButton.addStyleName("ComponentLink");
				buynowButton.addStyleName("index:" + i);
				vpanel3.add(buynowButton);
				vpanel3.setCellHorizontalAlignment(buynowButton, HasHorizontalAlignment.ALIGN_CENTER);

				Button detailsButton = new Button(controller.getCommonConstants().Details(), productClickHandler);
				detailsButton.addStyleName(getHandle() + "BodyTableButton");
				detailsButton.addStyleName("ComponentLink");
				detailsButton.addStyleName("index:" + i);
				vpanel3.add(detailsButton);
				vpanel3.setCellHorizontalAlignment(detailsButton, HasHorizontalAlignment.ALIGN_CENTER);

				Button writeReviewButton = new Button(constants.ProductReviewsComponentWriteReview(), writeReviewClickHandler);
				writeReviewButton.addStyleName(getHandle() + "BodyTableButton");
				writeReviewButton.addStyleName("ComponentLink");
				writeReviewButton.addStyleName("index:" + i);
				vpanel3.add(writeReviewButton);
				vpanel3.setCellHorizontalAlignment(writeReviewButton, HasHorizontalAlignment.ALIGN_CENTER);
			}

			cf.setHorizontalAlignment(i+1, 0, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setHorizontalAlignment(i+1, 2, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setStyleName(i+1, 0, getHandle() + "BodyTableCell");
			cf.setStyleName(i+1, 1, getHandle() + "BodyTableCell");
			cf.setStyleName(i+1, 2, getHandle() + "BodyTableCell");
			cf.addStyleName(i+1, 0, getHandle() + "BodyTableImage");
			cf.addStyleName(i+1, 1, getHandle() + "BodyTableData");
			cf.addStyleName(i+1, 2, getHandle() + "BodyTableButtons");
			bodyTable.setWidget(i+1, 0, vpanel1);
			bodyTable.setWidget(i+1, 1, vpanel2);
			bodyTable.setWidget(i+1, 2, vpanel3);

			productModelId = productModel.getId();
		}
		onBuilt();
	}

	protected ClickHandler productClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int index = Integer.parseInt(stylenames);
			ProductModel productModel = getProductModel(index);
			int mid = 0;
			if (!isClearManufacturerId()) mid = StoreComponentController.manufacturersComponent.getManufacturerModel().getId();
			onSelection("ProductComponent--" + productModel.getId() + "--"
					+ productModel.getCategoryId() + "--" 
					+ mid);
		}
	};

	protected ClickHandler cartClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int index = Integer.parseInt(stylenames);
			onCartSelection(index);
		}
	};

	protected ClickHandler writeReviewClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int index = Integer.parseInt(stylenames);
			ProductModel productModel = getProductModel(index);

			onSelection("CreateProductReviewComponent--0--" + productModel.getId() + "--" + productModel.getCategoryId()
					+ "--" + StoreComponentController.manufacturersComponent.getManufacturerModel().getId() + "--" + ProductReviewModel.PRODUCTREVIEWS);
		}
	};

	public class PRTableNavigatorCallback implements TableNavigatorWidgetCallback
	{
		public void onSelection(int offset)
		{
			productReviewModel.setOffset(offset);
			thisComponent.onSelection(getHistory());
		}

		public void onOrderby(String orderby)
		{
			productReviewModel.setOffset(0);
			productReviewModel.setOrderby(orderby);
			thisComponent.onSelection(getHistory());
		}
	}
	
	public String getHistory()
	{
		String history = "ProductReviewsComponent--";
		history += StoreComponentController.productComponent.getProductModel().getId() + "--";
		history += StoreComponentController.categoriesComponent.getCategoryModel().getId() + "--";
		history += StoreComponentController.manufacturersComponent.getManufacturerModel().getId() + "--";
		history += productReviewModel.getOffset() + "--";
		history += productReviewModel.getOrderby() + "--";
		
		return history;
	}

	public ProductReviewModel getProductReviewModel(int i) {
		return productReviewModels.get(i);
	}

	public ProductReviewModel getProductReviewModel() {
		return productReviewModel;
	}
}